import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class QuiverFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	private Configuration config;
	private static QuiverFrame instance;
	public JTabbedPane tabs;
    public JTextField relationInput;
    public JButton relationButton;
    public RelationListModel relationListModel;
    public JList relationList;
	public GAPInterface gapInterface;

	private QuiverFrame() {
		config = Configuration.getDefaultConfiguration();
		setJMenuBar(createMenu());
		tabs = createTabbedPane();

        relationInput = createRelationInput();
        relationButton = createRelationButton();
        relationListModel = createRelationListModel();
        relationList = createRelationList();

        this.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(config.deleteKey, "Delete selected nodes");
        this.getRootPane().getActionMap().put("Delete selected nodes", Actions.deleteSelectedNodesAction);

        layOutComponents();

		setTitle(config.windowTitle);
		setSize((int) config.windowWidth, (int) config.windowHeight);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
		setVisible(true);
	}

    public static QuiverFrame getInstance() {
		if (instance == null) {
			instance = new QuiverFrame();
		}
		return instance;
	}

    // START CREATE COMPONENTS //
	private JTextField createRelationInput() {
        final JTextField relationInput = new JTextField();


        relationInput.setFont(config.relationInputFont);

        relationInput.setAction(Actions.addRelationAction);

        relationInput.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent keyEvent) {
            }

            @Override
            public void keyPressed(KeyEvent keyEvent) {
            }

            @Override
            public void keyReleased(KeyEvent keyEvent) {
                if (Relation.validate(getActivePanel().quiver, relationInput.getText())) {
                    relationInput.setForeground(Color.BLACK);
                } else {
                    relationInput.setForeground(Color.RED);
                }
            }
        });

//        relationInput.setMaximumSize(new Dimension((int) config.windowWidth, 40));
        return relationInput;
    }
    
    private JButton createRelationButton() {
        final JButton relationButton = new JButton();
        relationButton.setAction(Actions.addRelationAction);
        relationButton.setText("Add");
        return relationButton;
    }
    
    private RelationListModel createRelationListModel() {
        return new RelationListModel(null);
    }
    
    private JList createRelationList() {
        final JList relationList = new JList<Relation>(relationListModel);
        
        relationList.setSelectionModel(new DefaultListSelectionModel() {
            @Override
            public void setSelectionInterval(int index0, int index1) {
                if (isSelectedIndex(index0)) {
                    super.removeSelectionInterval(index0, index1);
                } else {
                    super.setSelectionInterval(index0, index1);
                }
            }
        });

        relationList.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent keyEvent) {
            }

            @Override
            public void keyPressed(KeyEvent keyEvent) {
            }

            @Override
            public void keyReleased(KeyEvent keyEvent) {
                switch(keyEvent.getKeyCode()) {
                case KeyEvent.VK_DELETE:
                    if (relationList.getSelectedIndex() != -1) {
                        Relation relation = (Relation) relationList.getSelectedValue();
                        relation.setSelected(false);
                        getActivePanel().removeRelation(relation);
                        tabs.updateUI();
                    }
                    break;
                }
            }
        });
        
        relationList.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent listSelectionEvent) {
                for (int i = 0; i < relationList.getModel().getSize(); i++) {
                    Relation relation = (Relation) relationList.getModel().getElementAt(i);
                    relation.setSelected(false);
                }

                if (relationList.getSelectedIndex() == -1) {

                } else {
                    Relation relation = (Relation) relationList.getSelectedValue();
                    relation.setSelected(true);

                }
                relationList.updateUI();
                tabs.updateUI();
            }
        });

        return relationList;
    }
    
    private JTabbedPane createTabbedPane() {
		final JTabbedPane tabs = new JTabbedPane();
//        TabTitleEditListener titleEditor = new TabTitleEditListener(getInstance()); //fjernet pga problemer, se nederst
		tabs.setFocusTraversalKeysEnabled(false);
		InputMap im = tabs.getInputMap(JTabbedPane.WHEN_IN_FOCUSED_WINDOW);
		im.put(config.nextQuiverKey, "navigateRight");
		im.put(config.prevQuiverKey, "navigateLeft");

		tabs.addChangeListener(new ChangeListener() {

			@Override
			public void stateChanged(ChangeEvent arg0) {
				if (instance == null) {
					return;
				}
				QuiverPanel panel = instance.getActivePanel();
				if (panel == null) {
					return;
				}
                getActivePanel().updateUndoRedoActions();

                ((RelationListModel)relationList.getModel()).setRelations(panel.getRelations());

                //Updates the relationList to reflect the relations associated with the active quiver.
                relationList.updateUI();
			}
		});
//        tabs.addChangeListener(titleEditor);
//        tabs.addMouseListener(titleEditor);
		
		return tabs;
	}
    // END CREATE COMPONENTS //


    private void layOutComponents() {
        setLayout(new GridBagLayout());
        GridBagConstraints c1 = new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
                GridBagConstraints.BOTH, new Insets(5,5,5,5),  0, 0);
        c1.weightx = 0.75;
        c1.weighty = 0.95;

        add(tabs, c1);
        
        JPanel inputPanel = new JPanel();
        inputPanel.setLayout(new GridBagLayout());

        GridBagConstraints c2 = new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
                GridBagConstraints.BOTH, new Insets(5,5,5,5),  0, 0);

        c2.weightx = 0.9;

        inputPanel.add(relationInput, c2);

        c2.gridx = 1;
        c2.weightx = 0.1;

        inputPanel.add(relationButton, c2);

        c1.gridy = 1;
        c1.weighty = 0.05;
        
        add(inputPanel, c1);
        
        c1.gridy = 0;
        c1.gridx = 1;
        c1.gridheight = 2;
        c1.weighty = 1.0;
        c1.weightx = 0.25;

        add(relationList, c1);

        pack();
    }

    public String getRelationString() {
        return relationInput.getText();
    }

	public QuiverPanel getActivePanel() {
		return (QuiverPanel) tabs.getSelectedComponent();
	}

	public void renameActivePanel(String newName) {
		QuiverPanel activePanel = getActivePanel();
		activePanel.quiver.setName(newName);
		tabs.setTitleAt(tabs.getSelectedIndex(), activePanel.quiver.getName());
	}



    // START CREATE MENUS //
    private JMenu createFileMenu() {
        JMenu fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);

        JMenuItem openQuiverItem = new JMenuItem(Actions.openQuiverAction);
        openQuiverItem.setAccelerator(config.openQuiverKey);
        fileMenu.add(openQuiverItem);

        JMenuItem openQuiverSession = new JMenuItem(Actions.openQuiverSessionAction);
        openQuiverSession.setAccelerator(config.openQuiverSessionKey);
        fileMenu.add(openQuiverSession);

        fileMenu.addSeparator();

        JMenuItem saveQuiverItem = new JMenuItem(Actions.saveQuiverAction);
        saveQuiverItem.setAccelerator(config.saveQuiverKey);
        fileMenu.add(saveQuiverItem);

        JMenuItem saveQuiverSession = new JMenuItem(Actions.saveQuiverSessionAction);
        saveQuiverSession.setAccelerator(config.saveQuiverSessionKey);
        fileMenu.add(saveQuiverSession);

        fileMenu.addSeparator();

        JMenuItem saveLaTeXOutput = new JMenuItem(Actions.saveLaTeXOutputAction);
        fileMenu.add(saveLaTeXOutput);

        return fileMenu;
    }

	private JMenu createEditMenu() {
		JMenu editMenu = new JMenu("Edit");
		editMenu.setMnemonic(KeyEvent.VK_E);
		JMenuItem undoItem = new JMenuItem(Actions.undoAction);
		undoItem.setAccelerator(config.undoKey);
		editMenu.add(undoItem);
		JMenuItem redoItem = new JMenuItem(Actions.redoAction);
		redoItem.setAccelerator(config.redoKey);
		editMenu.add(redoItem);
		return editMenu;
	}

	private JMenu createQuiverMenu() {
		JMenu quiverMenu = new JMenu("Quiver");
		quiverMenu.setMnemonic(KeyEvent.VK_Q);
		JMenuItem newQuiverItem = new JMenuItem(Actions.newQuiverAction);
		newQuiverItem.setAccelerator(config.newQuiverKey);
		quiverMenu.add(newQuiverItem);
		JMenu loadMenu = new JMenu("Load");
		loadMenu.setMnemonic(KeyEvent.VK_L);
		JMenu standardQuiversMenu = new JMenu("Standard quivers");
		standardQuiversMenu.setMnemonic(KeyEvent.VK_S);
		standardQuiversMenu.add(new JMenuItem(Actions.loadAnAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadDnAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadEnAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadCycleAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadWheelAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadStarAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadFriendshipAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadCompleteAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadPyramidAction));
		loadMenu.add(standardQuiversMenu);
		quiverMenu.add(loadMenu);
		JMenuItem renameQuiverItem = new JMenuItem(Actions.renameAction);
		renameQuiverItem.setAccelerator(config.renameQuiverKey);
		quiverMenu.add(renameQuiverItem);
		JMenuItem closeQuiverItem = new JMenuItem(Actions.closeQuiverAction);
		closeQuiverItem.setAccelerator(config.closeQuiverKey);
		quiverMenu.add(closeQuiverItem);
		JMenuItem clearItem = new JMenuItem(Actions.clearAction);
		clearItem.setAccelerator(config.clearQuiverKey);
		quiverMenu.add(clearItem);
		JMenuItem snapItem = new JMenuItem(Actions.snapAction);
		snapItem.setAccelerator(config.snapKey);
		quiverMenu.add(snapItem);
		JMenuItem arrangeItem = new JMenuItem(Actions.arrangeAction);
		arrangeItem.setAccelerator(config.arrangeKey);
		quiverMenu.add(arrangeItem);
		return quiverMenu;
	}

    private JMenu createFieldMenu() {
        JMenu fieldMenu = new JMenu("Field");
        fieldMenu.add(new JMenuItem(Actions.setFiniteFieldAction));
        fieldMenu.add(new JMenuItem(Actions.resetToRationalsAction));
        return fieldMenu;
    }
    
	private JMenu createRepresentationMenu() {
		JMenu representationMenu = new JMenu("Representation");
		representationMenu.add(new JMenuItem(Actions.newRepresentationAction));
		return representationMenu;
	}

	private JMenu createGAPMenu() {
		JMenu gapMenu = new JMenu("GAP");
		gapMenu.setMnemonic(KeyEvent.VK_G);
		gapMenu.add(new JMenuItem(Actions.startGAPAction));
		gapMenu.add(new JMenuItem(Actions.saveGAPSessionAction));
		gapMenu.add(new JMenuItem(Actions.showGAPInterfaceAction));
		gapMenu.add(new JMenuItem(Actions.quiverProductGAPAction));
		gapMenu.add(new JMenuItem(Actions.sendQuiversGAPAction));
        gapMenu.add(new JMenuItem(Actions.setupBasicsGAPAction));
		return gapMenu;
	}

	private JMenu createOptionsMenu() {
		JMenu optionsMenu = new JMenu("Options");
		optionsMenu.setMnemonic(KeyEvent.VK_O);
		JCheckBoxMenuItem toggleGridItem = new JCheckBoxMenuItem(
				Actions.toggleGridAction);
		toggleGridItem.setSelected(config.gridVisible);
		optionsMenu.add(toggleGridItem);
		JCheckBoxMenuItem toggleLabelItem = new JCheckBoxMenuItem(
				Actions.toggleLabelAction);
		toggleLabelItem.setSelected(config.showLabels);
		optionsMenu.add(toggleLabelItem);
		JCheckBoxMenuItem autoArrangeItem = new JCheckBoxMenuItem(
				Actions.autoArrangeAction);
		autoArrangeItem.setSelected(config.autoArrangeQuiver);
		optionsMenu.add(autoArrangeItem);
		return optionsMenu;
	}

	private JMenuBar createMenu() {
		JMenuBar menuBar = new JMenuBar();
        menuBar.add(createFileMenu());
		menuBar.add(createEditMenu());
		menuBar.add(createQuiverMenu());
        menuBar.add(createFieldMenu());
		menuBar.add(createRepresentationMenu());
		menuBar.add(createGAPMenu());
		menuBar.add(createOptionsMenu());
		return menuBar;
	}
    // END CREATE MENUS //



	public void addTab(Quiver quiver, boolean active) {
        config.representationMode = false;
		QuiverPanel panel = new QuiverPanel(quiver);
		tabs.addTab(quiver.getName(), panel);
		if (active) {
			tabs.setSelectedIndex(tabs.getTabCount() - 1);
		}
	}
    public void addTab(QuiverPanel qp, boolean active) {
        config.representationMode = false;
        tabs.addTab(qp.quiver.getName(), qp);
        if (active) {
            tabs.setSelectedIndex(tabs.getTabCount() -1);
        }
    }
    
	public void addTab(boolean active) {
		Quiver quiver = new Quiver();
		addTab(quiver, active);
	}

	public void closeTab() {
		tabs.remove(tabs.getSelectedIndex());
		if (tabs.getTabCount() == 0) {
			addTab(true);
		}
	}

	public ArrayList<Quiver> getQuivers() {
		ArrayList<Quiver> quivers = new ArrayList<Quiver>();
		for (Component c : tabs.getComponents()) {
            try {
                QuiverPanel panel = (QuiverPanel) c;
                quivers.add(panel.quiver);
            } catch (ClassCastException e) {

            }

		}
		return quivers;
	}
    public ArrayList<QuiverPanel> getQuiverPanels() {
        ArrayList<QuiverPanel> quiverPanels = new ArrayList<QuiverPanel>();
        for (Component c: tabs.getComponents()) {
            try {
                QuiverPanel panel = (QuiverPanel) c;
                if (!panel.quiver.isEmpty()) {
                    quiverPanels.add(panel);
                }
            } catch (ClassCastException e) {

            }
        }
        return quiverPanels;
    }

	public Set<String> getNamePool() {
		Set<String> pool = new HashSet<String>();
		QuiverPanel panel = getActivePanel();
		Quiver quiver = panel.quiver;
		for (Arrow arrow : quiver.getArrows()) {
			pool.add(arrow.getName());
		}
		for (Node node : quiver.getNodes()) {
			pool.add(node.getName());
		}
		for (Representation r : panel.getRepresentations()) {
			pool.add(r.getName());
		}
		pool.add(quiver.getName());
		return pool;
	}

	public void reEvaluateNames(){
		QuiverPanel panel = getActivePanel();
		Quiver quiver = panel.quiver;
		for (Node node : quiver.getNodes()){
			node.setName();
		}
		for (Arrow arrow : quiver.getArrows()){
			arrow.setName();
		}
	}
	
	public boolean isUsedName(String name) {
		return getNamePool().contains(name);

	}
}
/* //fungerer sort of, men navn lagres ikke med tabben og koden er ikke særlig pen
class TabTitleEditListener extends MouseAdapter implements ChangeListener{
    private final JTextField editor = new JTextField();
    private final JTabbedPane tabbedPane;
    private final QuiverFrame frame;
    public TabTitleEditListener(QuiverFrame frame) {
        this.frame = frame;
        tabbedPane = frame.tabs;
        editor.setBorder(BorderFactory.createEmptyBorder());
        editor.addFocusListener(new FocusAdapter() {
            @Override public void focusLost(FocusEvent e) {
                renameTabTitle();
            }
        });
        editor.addKeyListener(new KeyAdapter() {
            @Override public void keyPressed(KeyEvent e) {
                if(e.getKeyCode()==KeyEvent.VK_ENTER) {
                    renameTabTitle();
                }else if(e.getKeyCode()==KeyEvent.VK_ESCAPE) {
                    cancelEditing();
                }else{
                    editor.setPreferredSize((editor.getText().length()>len)?null:dim);
                    tabbedPane.revalidate();
                }
            }
        });
        tabbedPane.getInputMap(JComponent.WHEN_FOCUSED).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "start-editing");
        tabbedPane.getActionMap().put("start-editing", new AbstractAction() {
            @Override public void actionPerformed(ActionEvent e) {
                startEditing();
            }
        });
    }
    @Override public void stateChanged(ChangeEvent e) {
        renameTabTitle();
    }
    @Override public void mouseClicked(MouseEvent me) {
        Rectangle rect = tabbedPane.getUI().getTabBounds(tabbedPane, tabbedPane.getSelectedIndex());
        if(rect!=null && rect.contains(me.getPoint()) && me.getClickCount()==2) {
            startEditing();
        }else{
            renameTabTitle();
        }
    }
    private int editing_idx = -1;
    private int len = -1;
    private Dimension dim;
    private Component tabComponent = null;
    private void startEditing() {
        editing_idx = tabbedPane.getSelectedIndex();
        tabComponent = tabbedPane.getTabComponentAt(editing_idx);
        tabbedPane.setTabComponentAt(editing_idx, editor);
        editor.setVisible(true);
        editor.setText(tabbedPane.getTitleAt(editing_idx));
        editor.selectAll();
        editor.requestFocusInWindow();
        len = editor.getText().length();
        dim = editor.getPreferredSize();
        editor.setMinimumSize(dim);
    }
    private void cancelEditing() {
        if(editing_idx>=0) {
            tabbedPane.setTabComponentAt(editing_idx, tabComponent);
            editor.setVisible(false);
            editing_idx = -1;
            len = -1;
            tabComponent = null;
            editor.setPreferredSize(null);
            tabbedPane.requestFocusInWindow();
        }
    }
    private void renameTabTitle() {
        String title = editor.getText().trim();
        if(editing_idx>=0 && !title.isEmpty()) {
            frame.renameActivePanel(title);
            frame.revalidate();
            //tabbedPane.setTitleAt(editing_idx, title);
        }
        cancelEditing();
    }
}*/
